<template>
  <el-scrollbar height="100vh">
    <div class="container">
      <el-affix :offset="1">
        <h1 class="title">标记点 marker，鼠标移动到点展示信息</h1>
      </el-affix>
      <div id="map" class="map-x" ref="mapBox"></div>
      <div class="txt" ref="beijingTxtBox">首都北京</div>
      <div class="marker" title="Marker" ref="beijingMarkerBox"></div>
      <div ref="popup" class="popup" v-show="shopPopup">
        <p class="pop-head">{{pop.name}}</p>
        <p class="pRow">
          <label class="labelKey">编码</label>
          <span class="spVal">{{pop.id}}</span>
        </p>
        <p class="pRow">
          <label class="labelKey">时间</label>
          <span class="spVal">{{pop.content}}</span>
        </p>
      </div>
      <div class="codestyle"><Code /></div>
      <dl>
        <p>注意点</p>
        <dt>overlay(叠加层)</dt>
        <dd>即叠加到地图上显示的元素， 关联了一个自定义的HTML元素，由一个单一的地图坐标点确定叠加位置。 与控件类似，但不同的是叠加元素不是在一个固定的屏幕位置上， 而是通过关联一个地图逻辑坐标点跟随地图移动，如标注点、popup等。</dd>
        <p>创建marker，text时，先创建overlay，然后将其添加到Map中即可，但要想修改鼠标样式，必须创建Feature，可以是(点point)，(线LineString)，(面Polygon)，添加到Map，然后判断有无Feature修改鼠标样式。</p>
        <dt>改变鼠标放到图层时改变鼠标样式</dt>
        <dd>state.map.getTargetElement().style.cursor = state.map.hasFeatureAtPixel(evt.pixel) ? 'pointer' : ''</dd>
        <dt>获取图层</dt>
        <dd>const feature = state.map.forEachFeatureAtPixel(evt.pixel, feature => feature)</dd>
        <p>如不想要鼠标移动到点弹窗弹框，点击 <router-link :to="{path: '/popup'}"><span style="color: blue">popup</span></router-link> 案例，修改弹出框的样式为点样式，然后state.map.addOverlay(marker); 添加图形标记即可。</p>
      </dl>
    </div>
  </el-scrollbar>
</template>
<script>
import { reactive, toRefs, ref, onMounted } from 'vue-demi'
import { toRaw } from '@vue/reactivity'
import 'ol/ol.css'
import { Map, View } from 'ol'
import XYZ from 'ol/source/XYZ' // 引入XYZ地图格式
import { fromLonLat } from 'ol/proj'
import Overlay from 'ol/Overlay.js'
import Point from 'ol/geom/Point'
import Feature from 'ol/Feature'
import VectorSource from 'ol/source/Vector'
import { Tile as TileLayer, Vector as VectorLayer } from 'ol/layer'
import Code from './code.vue'
export default {
  setup () {
    const state = reactive({
      map: null,
      mapBox: ref(null),
      beijingTxtBox: ref(null), // 文字特性容器
      beijingMarkerBox: ref(null), // 标记点特性容器
      popup: ref(null),
      shopPopup: false,
      pos: fromLonLat([116.41400, 39.91500]), // 北京坐标
      beijingMarker: null,
      beijingTxt: null,
      iconFeature: null,
      overlay: null,
      pointData: {
        id: '10000000',
        content: '这是创建图层时给这个点的数据'
      },
      pop: {} // 弹窗里的数据
    })
    const init = () => {
      // 创建北京坐标点文字特性
      state.beijingTxt = new Overlay({
        position: state.pos,
        element: state.beijingTxtBox,
        offset: [-25, 14]
      })

      // 创建北京坐标点圆点特性
      state.beijingMarker = new Overlay({
        position: state.pos,
        positioning: 'center-center', // 如果不配置，则圆的左上角和坐标点对其
        element: state.beijingMarkerBox,
        stopEvent: false // 不阻止默认事件，比如鼠标放到圆点上时，滚动鼠标滚轮，也可以缩放地图
      })

      // 创建点图层并添加到map
      state.iconFeature = new Feature({
        geometry: new Point(state.pos),
        name: '首都北京',
        population: 4000,
        rainfall: 500
      })
      state.iconFeature.setProperties(state.pointData, false)

      state.map = new Map({
        target: state.mapBox, // 视图容器id
        layers: [
          new VectorLayer({ // 创建矢量图层
            source: new VectorSource({ // 创建矢量容器，将图标特性添加进容器中
              features: [state.iconFeature]
            })
          }),
          new TileLayer({
            source: new XYZ({
              url: 'http://map.geoq.cn/ArcGIS/rest/services/ChinaOnlineStreetPurplishBlue/MapServer/tile/{z}/{y}/{x}'
            })
          })
        ],
        overlays: [state.beijingMarker, state.beijingTxt], // 也可以将标识这么添加
        view: new View({
          // 地图视图
          center: state.pos, // 北京坐标
          minZoom: 1, // 地图缩放最小级别
          zoom: 4 // 地图缩放级别（打开页面时默认级别）
        })
      })

      // state.map.addOverlay(state.beijingMarker) // 将圆点标识添加到地图
      // state.map.addOverlay(state.beijingTxt) // 将文字标识添加到地图

      mapPointermove()
    }

    const mapPointermove = () => {
      state.map.on('pointermove', function (evt) {
        // 创建弹窗并添加到Map
        state.overlay = new Overlay({
          element: state.popup,
          offset: [-180, -110]
        })
        state.map.addOverlay(state.overlay)

        // 鼠标放到图层时改变鼠标样式
        state.map.getTargetElement().style.cursor = state.map.hasFeatureAtPixel(evt.pixel) ? 'pointer' : ''

        // 获取图层
        const feature = state.map.forEachFeatureAtPixel(evt.pixel, function (feature) {
          return feature
        })

        // 判断如果有图层时显示弹窗否则不显示
        if (feature) {
          state.shopPopup = true
          state.overlay.setPosition(evt.coordinate)
          state.pop = toRaw(feature.values_)
        } else {
          state.shopPopup = false
        }
      })
    }

    onMounted(() => {
      init()
    })
    return {
      ...toRefs(state)
    }
  },
  components: {
    Code
  }
}
</script>
<style lang="scss" scoped>
@import '../../css/main.scss';
.marker {
  width: 0;
  height: 0;
  border-left: 10px solid transparent;
  border-right: 10px solid transparent;
  border-bottom: 20px solid blue;
}
.txt {
  text-decoration: none;
  color: red;
  font-size: 11pt;
  font-weight: bold;
}
.popup {
  border-radius: 4px;
  box-shadow: 0 0 5px #c2cad8;
  min-width: 240px;
  border: 1px solid #60626614;
  box-sizing: border-box;
  border-radius: 4px;
  background: #fff;
  padding: 4px !important;
  color: #000;
  .pop-head {
    height: 30px;
    background: #1c5cb8;
    border-radius: 4px 4px 0 0;
    color: #fff;
    padding: 0 8px;
    display: flex;
    justify-content: space-between;
    align-items: center;
  }
  .pRow {
    display: flex;
    border-bottom: 1px solid #9eb7e838;
    box-sizing: border-box;
    margin-bottom: 1px;
    .labelKey {
      width: 100px;
      padding: 4px 8px 4px 0;
      text-align: right;
      flex: none;
      font-weight: 500;
      background: #ecf5ff;
    }
    .labelKey::after {
      content: '：';
    }
    .spVal {
      flex: auto;
      text-align: left;
      padding: 4px 0 4px 8px;
      font-weight: 600;
    }
  }
  &::after {
    content: '';
    display: block;
    position: absolute;
    width: 20px;
    height: 20px;
    background: #fff;
    bottom: -10px;
    left: 50%;
    z-index: -1;
    transform: translateX(-50%) rotate(45deg);
  }
}
</style>
